-
Notifications
You must be signed in to change notification settings - Fork 3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix: Room - Create room whisper reappears when interacting with it after workspace is deleted. #50692
Conversation
…ter workspace is deleted. Signed-off-by: krishna2323 <[email protected]>
@rayane-djouah Please copy/paste the Reviewer Checklist from here into a new comment on this PR and complete it. If you have the K2 extension, you can simply click: [this button] |
Signed-off-by: krishna2323 <[email protected]>
Signed-off-by: krishna2323 <[email protected]>
Signed-off-by: krishna2323 <[email protected]>
Signed-off-by: krishna2323 <[email protected]>
src/libs/ReportActionsUtils.ts
Outdated
@@ -28,6 +28,7 @@ import * as PersonalDetailsUtils from './PersonalDetailsUtils'; | |||
import * as PolicyUtils from './PolicyUtils'; | |||
import * as ReportConnection from './ReportConnection'; | |||
import type {OptimisticIOUReportAction, PartialReportAction} from './ReportUtils'; | |||
import {canUserPerformWriteAction, getReport} from './ReportUtils'; | |||
import StringUtils from './StringUtils'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@rayane-djouah, I'm not sure how to fix this warning :(, please let me know if you have some any idea how to fix this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Krishna2323 Let's call canUserPerformWriteAction
function in components instead of in the shouldReportActionBeVisible
utility function and then pass a boolean to shouldReportActionBeVisible
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@rayane-djouah, I found using reportID
cleaner instead of using canUserPerformWriteAction
in components and then passing it to shouldReportActionBeVisible
but let me know if you still think the other way. I will make those changes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can't use functions from ReportUtils
in ReportActionsUtils
because ReportUtils
depends on functions from ReportActionsUtils
, which would create a circular dependency.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@rayane-djouah, should we create the same functions in ReportActionsUtils
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This would result in code duplication. According to the author and reviewer checklist:
I verified all code is DRY (the PR doesn't include any logic written more than once, with the exception of tests)
Therefore, we should avoid duplicating functions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's call
canUserPerformWriteAction
function in components instead of in the shouldReportActionBeVisible utility function and then pass a boolean to shouldReportActionBeVisible
@rayane-djouah, then we can do this but then we have to get the report using getReport
function in every file which only have the reportID and then we can use canUserPerformWriteAction
and pass the result to shouldReportActionBeVisible
. WDYT?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using getReport
function (or useOnyx
hook) sounds good to me 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sorry for delay, will provide updates within 24hours.
@Krishna2323 Could you please share an update? Thanks! |
src/libs/ReportActionsUtils.ts
Outdated
) { | ||
return false; | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@rayane-djouah, if we pass canUserPerformWriteAction
boolean to shouldReportActionBeVisible
then how we will get the reportID
for isActionableJoinRequestPending
, should we pass both?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Krishna2323 Can we use reportAction?.reportID
instead?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@rayane-djouah, reportAction?.reportID
is undefined.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Krishna2323 Then I think we need to pass both
@Krishna2323 Let's pass both parameters. We also have conflicts. |
@Krishna2323 Friendly bump |
Sorry for delay, I will provide updates today. |
Signed-off-by: krishna2323 <[email protected]>
Signed-off-by: krishna2323 <[email protected]>
Signed-off-by: krishna2323 <[email protected]>
Signed-off-by: krishna2323 <[email protected]>
Signed-off-by: krishna2323 <[email protected]>
Signed-off-by: krishna2323 <[email protected]>
@Krishna2323 Performance Tests are failing |
src/libs/ReportActionsUtils.ts
Outdated
@@ -635,7 +635,11 @@ const supportedActionTypes: ReportActionName[] = [...Object.values(otherActionTy | |||
* Checks if a reportAction is fit for display, meaning that it's not deprecated, is of a valid | |||
* and supported type, it's not deleted and also not closed. | |||
*/ | |||
function shouldReportActionBeVisible(reportAction: OnyxEntry<ReportAction>, key: string | number): boolean { | |||
function shouldReportActionBeVisible(reportAction: OnyxEntry<ReportAction>, key: string | number, reportID: string, canUserPerformWriteAction?: boolean): boolean { | |||
if ((isActionableReportMentionWhisper(reportAction) || isActionableJoinRequestPending(reportID ?? '-1') || isActionableMentionWhisper(reportAction)) && !canUserPerformWriteAction) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reviewing the code here:
App/src/libs/ReportActionsUtils.ts
Lines 1480 to 1502 in bef062b
/** | |
* Checks if a given report action corresponds to a join request action. | |
* @param reportAction | |
*/ | |
function isActionableJoinRequest(reportAction: OnyxEntry<ReportAction>): reportAction is ReportAction<typeof CONST.REPORT.ACTIONS.TYPE.ACTIONABLE_JOIN_REQUEST> { | |
return isActionOfType(reportAction, CONST.REPORT.ACTIONS.TYPE.ACTIONABLE_JOIN_REQUEST); | |
} | |
function getActionableJoinRequestPendingReportAction(reportID: string): OnyxEntry<ReportAction> { | |
const findPendingRequest = Object.values(getAllReportActions(reportID)).find( | |
(reportActionItem) => isActionableJoinRequest(reportActionItem) && getOriginalMessage(reportActionItem)?.choice === ('' as JoinWorkspaceResolution), | |
); | |
return findPendingRequest; | |
} | |
/** | |
* Checks if any report actions correspond to a join request action that is still pending. | |
* @param reportID | |
*/ | |
function isActionableJoinRequestPending(reportID: string): boolean { | |
return !!getActionableJoinRequestPendingReportAction(reportID); | |
} |
I suggest we create a function named isActionableJoinRequestPendingReportAction
and refactor the code accordingly:
function isActionableJoinRequestPendingReportAction(reportAction: OnyxEntry<ReportAction>): boolean {
return isActionableJoinRequest(reportAction) && getOriginalMessage(reportAction)?.choice === ('' as JoinWorkspaceResolution);
}
function getActionableJoinRequestPendingReportAction(reportID: string): OnyxEntry<ReportAction> {
const findPendingRequest = Object.values(getAllReportActions(reportID)).find((reportActionItem) => isActionableJoinRequestPendingReportAction(reportActionItem));
return findPendingRequest;
}
Then use isActionableJoinRequestPendingReportAction
in the following manner:
if ((isActionableReportMentionWhisper(reportAction) || isActionableJoinRequestPending(reportID ?? '-1') || isActionableMentionWhisper(reportAction)) && !canUserPerformWriteAction) { | |
if ((isActionableReportMentionWhisper(reportAction) || isActionableJoinRequestPendingReportAction(reportAction) || isActionableMentionWhisper(reportAction)) && !canUserPerformWriteAction) { |
This refactor eliminates the need for the reportID
parameter.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done.
if (!reportAction) { | ||
return false; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's keep this if block first
) { | ||
const targetNote = privateNotes?.[Number(accountID)]?.note ?? ''; | ||
const attachments: Attachment[] = []; | ||
const report = ReportUtils.getReport(reportID); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const report = ReportUtils.getReport(reportID); | |
const [report] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${reportID}`); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
extractAttachments
is a util function so we can't use useOnyx
here.
|
||
const sortedReportActions = ReportActionsUtils.getSortedReportActionsForDisplay(itemReportActions, reportID, ReportUtils.canUserPerformWriteAction(itemFullReport)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const sortedReportActions = ReportActionsUtils.getSortedReportActionsForDisplay(itemReportActions, reportID, ReportUtils.canUserPerformWriteAction(itemFullReport)); | |
const canUserPerformWriteAction = ReportUtils.canUserPerformWriteAction(itemFullReport); | |
const sortedReportActions = ReportActionsUtils.getSortedReportActionsForDisplay(itemReportActions, reportID, canUserPerformWriteAction); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done.
@@ -29,6 +30,8 @@ function ParentNavigationSubtitle({parentNavigationSubtitleData, parentReportAct | |||
const {workspaceName, reportName} = parentNavigationSubtitleData; | |||
const {isOffline} = useNetwork(); | |||
const {translate} = useLocalize(); | |||
const report = ReportUtils.getReport(parentReportID); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const report = ReportUtils.getReport(parentReportID); | |
const [report] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${reportID}`); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done.
@@ -11,10 +12,12 @@ function usePaginatedReportActions(reportID?: string, reportActionID?: string) { | |||
// Use `||` instead of `??` to handle empty string. | |||
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing | |||
const reportIDWithDefault = reportID || '-1'; | |||
const report = ReportUtils.getReport(reportIDWithDefault); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const report = ReportUtils.getReport(reportIDWithDefault); | |
const [report] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${reportID}`); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
usePaginatedReportActions
is a util function so we can't use useOnyx here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
useOnyx
is already a part of this file, so I assume it works just fine? Generally, ReportUtils.getReport()
should be avoided because anything that it returns won't get updated if the onyx data updates.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry my mistake, now updated.
@@ -21,9 +22,11 @@ type DebugReportActionsProps = { | |||
function DebugReportActions({reportID}: DebugReportActionsProps) { | |||
const {translate, datetimeToCalendarTime} = useLocalize(); | |||
const styles = useThemeStyles(); | |||
const report = ReportUtils.getReport(reportID); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const report = ReportUtils.getReport(reportID); | |
const [report] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${reportID}`); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done.
I will work on the suggested changes today. |
Reviewer Checklist
Screenshots/VideosAndroid: NativeScreen.Recording.2024-11-13.at.5.21.14.PM.movAndroid: mWeb ChromeScreen.Recording.2024-11-13.at.5.23.59.PM.moviOS: NativeSimulator.Screen.Recording.-.iPhone.15.Pro.Max.-.2024-11-13.at.17.16.28.mp4iOS: mWeb SafariSimulator.Screen.Recording.-.iPhone.15.Pro.Max.-.2024-11-13.at.17.19.37.mp4MacOS: Chrome / SafariScreen.Recording.2024-11-13.at.5.04.57.PM.movMacOS: DesktopScreen.Recording.2024-11-13.at.5.08.43.PM.mov |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM and tests well 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there already a unit test explicitly for what is being fixed here? If not, please add one.
@@ -11,10 +12,12 @@ function usePaginatedReportActions(reportID?: string, reportActionID?: string) { | |||
// Use `||` instead of `??` to handle empty string. | |||
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing | |||
const reportIDWithDefault = reportID || '-1'; | |||
const report = ReportUtils.getReport(reportIDWithDefault); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
useOnyx
is already a part of this file, so I assume it works just fine? Generally, ReportUtils.getReport()
should be avoided because anything that it returns won't get updated if the onyx data updates.
Signed-off-by: krishna2323 <[email protected]>
@Krishna2323 Let's add a test case (for actionable whispers in archived reports) in tests/unit/ReportActionsUtilsTest.ts for App/tests/unit/ReportActionsUtilsTest.ts Line 313 in 9228354
App/tests/unit/ReportActionsUtilsTest.ts Line 208 in 9228354
App/tests/unit/ReportActionsUtilsTest.ts Line 408 in 9228354
|
Signed-off-by: krishna2323 <[email protected]>
Signed-off-by: krishna2323 <[email protected]>
Signed-off-by: krishna2323 <[email protected]>
Signed-off-by: krishna2323 <[email protected]>
@rayane-djouah test case added for for actionable whispers in archived reports. |
tests/unit/ReportActionsUtilsTest.ts
Outdated
input.pop(); | ||
expect(result).toStrictEqual(input); | ||
}); | ||
|
||
it('should filter whisper action in a archived report', () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you please follow the directions here for adding good comments to the tests?
input.pop(); | ||
expect(result).toStrictEqual(input); | ||
}); | ||
|
||
it('should filter whisper action in a archived report', () => { | ||
const input: ReportAction[] = [ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is all this data necessary for the test?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@tgolen, yes, it's necessary for checking that other types of actions aren't being filtered.
edit: I have updated the input data according to the test.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, I can see how it would be helpful to have some non-actionable whisper action types, but I don't think it's necessary to have all of CREATED, ADD_COMMENT, and CLOSED. I would suggest only having one of them (maybe ADD_COMMENT since that is pretty typical).
If you feel that CREATED and CLOSED is necessary to include, please explain it better why they are necessary as maybe I don't fully understand it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
CREATED
and CLOSED
type actions aren't necessary, removed them from the input and only kept ADD_COMMENT
.
Signed-off-by: krishna2323 <[email protected]>
tests/unit/ReportActionsUtilsTest.ts
Outdated
|
||
const result = ReportActionsUtils.getSortedReportActionsForDisplay(input, false); | ||
// Expected output should filter out actionable whisper actions type e.g. "join", "create room" | ||
// because "canUserPerformWriteAction" is false (report is archived) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@rayane-djouah @tgolen, are these comments enough for the explanation? Sorry for the trouble, I'm writing unit tests for the first time :(
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No worries! You'll get there. A few things:
These comments don't match the instructions I had you look at (it's OK, these are new instructions that we're trying for the first time, so you're also helping me improve the instructions!)
Can you please:
- Add three separate comments, each for the "Given", "When", and "Then" sections
- Have each comment explain WHY the code is there like it is
- Look at other tests in the code using this format to get some ideas (search for
// Given
). They won't always be the best examples, but you'll get a better idea of what I'm asking for
I'll add some suggestions to your tests here to explain what I mean
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the help 🙏🏻. I now have a better understanding of how the "Given," "When," and "Then" sections should be written. I’ve updated the comments (mostly copied from your suggestions 🫠).
tests/unit/ReportActionsUtilsTest.ts
Outdated
|
||
const result = ReportActionsUtils.getSortedReportActionsForDisplay(input, false); | ||
// Expected output should filter out actionable whisper actions type e.g. "join", "create room" | ||
// because "canUserPerformWriteAction" is false (report is archived) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No worries! You'll get there. A few things:
These comments don't match the instructions I had you look at (it's OK, these are new instructions that we're trying for the first time, so you're also helping me improve the instructions!)
Can you please:
- Add three separate comments, each for the "Given", "When", and "Then" sections
- Have each comment explain WHY the code is there like it is
- Look at other tests in the code using this format to get some ideas (search for
// Given
). They won't always be the best examples, but you'll get a better idea of what I'm asking for
I'll add some suggestions to your tests here to explain what I mean
input.pop(); | ||
expect(result).toStrictEqual(input); | ||
}); | ||
|
||
it('should filter actionable whisper actions e.g. "join", "create room" when room is archived', () => { | ||
const input: ReportAction[] = [ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const input: ReportAction[] = [ | |
// Given several different action types, including actionable whispers for creating and joining rooms, as well as non-actionable whispers | |
// - CREATED | |
// - ADD_COMMENT | |
// - ACTIONABLE_REPORT_MENTION_WHISPER | |
// - ACTIONABLE_MENTION_WHISPER | |
// - CLOSED | |
const input: ReportAction[] = [ |
tests/unit/ReportActionsUtilsTest.ts
Outdated
// Expected output should filter out actionable whisper actions type e.g. "join", "create room" | ||
// because "canUserPerformWriteAction" is false (report is archived) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// Expected output should filter out actionable whisper actions type e.g. "join", "create room" | |
// because "canUserPerformWriteAction" is false (report is archived) | |
// Then the output should correctly filter out the actionable whisper types for "join" and "create room" | |
// because the report is archived and making those actions not only doesn't make sense from a UX standpoint, but leads to server errors since those actions aren't possible. |
tests/unit/ReportActionsUtilsTest.ts
Outdated
// Expected output should filter out actionable whisper actions type e.g. "join", "create room" | ||
// because "canUserPerformWriteAction" is false (report is archived) | ||
// eslint-disable-next-line rulesdir/prefer-at | ||
const expectedOutput: ReportAction[] = [...input.slice(1, 3), input[0]]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[...input.slice(1, 3), input[0]];
is not very clear that it's specifically filtering out the actionable whispers. I suggest modifying this to use .filter()
and filter based on the actionName
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
updated to use filter()
method.
input.pop(); | ||
expect(result).toStrictEqual(input); | ||
}); | ||
|
||
it('should filter whisper action in a archived report', () => { | ||
const input: ReportAction[] = [ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, I can see how it would be helpful to have some non-actionable whisper action types, but I don't think it's necessary to have all of CREATED, ADD_COMMENT, and CLOSED. I would suggest only having one of them (maybe ADD_COMMENT since that is pretty typical).
If you feel that CREATED and CLOSED is necessary to include, please explain it better why they are necessary as maybe I don't fully understand it.
Signed-off-by: krishna2323 <[email protected]>
Signed-off-by: krishna2323 <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That looks really good now! Nice work. I just noticed this one last thing.
Signed-off-by: krishna2323 <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks very good! Thank you!
✋ This PR was not deployed to staging yet because QA is ongoing. It will be automatically deployed to staging after the next production release. |
🚀 Deployed to staging by https://github.com/tgolen in version: 9.0.65-0 🚀
|
🚀 Deployed to production by https://github.com/chiragsalian in version: 9.0.65-5 🚀
|
), | ||
[sortedReportActions, isOffline], | ||
[sortedReportActions, isOffline, report], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Having the report here was retriggering the memo block multiple times, which caused this blocker #52891
@@ -11,10 +12,12 @@ function usePaginatedReportActions(reportID?: string, reportActionID?: string) { | |||
// Use `||` instead of `??` to handle empty string. | |||
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing | |||
const reportIDWithDefault = reportID || '-1'; | |||
const [report] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${reportID}`); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FYI, we need to use reportIDWithDefault
here. This caused this issue: #52864
Explanation of Change
shouldReportActionBeVisible
to also includecanUserPerformWriteAction
check for the whisper actions.Fixed Issues
$ #49940
PROPOSAL: #49940 (comment)
Tests
Offline tests
QA Steps
// TODO: These must be filled out, or the issue title must include "[No QA]."
PR Author Checklist
### Fixed Issues
section aboveTests
sectionOffline steps
sectionQA steps
sectiontoggleReport
and notonIconClick
)src/languages/*
files and using the translation methodSTYLE.md
) were followedAvatar
, I verified the components usingAvatar
are working as expected)StyleUtils.getBackgroundAndBorderStyle(theme.componentBG)
)Avatar
is modified, I verified thatAvatar
is working as expected in all cases)Design
label and/or tagged@Expensify/design
so the design team can review the changes.ScrollView
component to make it scrollable when more elements are added to the page.main
branch was merged into this PR after a review, I tested again and verified the outcome was still expected according to theTest
steps.Screenshots/Videos
Android: Native
android_native.mp4
Android: mWeb Chrome
android_chrome.mp4
iOS: Native
ios_native.mp4
iOS: mWeb Safari
ios_safari.mp4
MacOS: Chrome / Safari
web_chrome.mp4
MacOS: Desktop
desktop_app.mp4